home *** CD-ROM | disk | FTP | other *** search
- // PetriDish.m
- // By Charles G. Fleming, Educational Computing Services, Allegheny College.
- // You may freely copy, distribute and reuse this code.
- // Allegheny College and the author disclaim any warranty of any kind,
- // expressed or implied, as to its fitness for any particular use.
- // This work was partially supported by a grant from the Vira Heinz Endowment.
-
- #import "PetriDish.h"
- #import "DrawPetriDish.h"
-
- #import <appkit/color.h>
- #import <appkit/NXImage.h>
- #import <appkit/Window.h>
- #import <appkit/TextField.h>
- #import <appkit/NXImage.h>
- #import <appkit/NXCursor.h>
- #import <appkit/View.h>
-
- #import <dpsclient/wraps.h>
-
- #import <stdlib.h>
- #import <math.h>
- #import <libc.h>
-
- #define ONECENTIMETER 28.3465 // Assuming 72 dpi.
- #define ONEMILLIMETER 2.83465;
-
- @implementation PetriDish
-
- - (const char *)inspectorName
- {
- return "PetriDishInspector";
- }
-
- // This is called when the view is resized in Interface Builder and when the OK button is pushed.
- // We will force the shape to be square. Redraw the petri dish in a new NXImage, then display it.
- - setFrame:(const NXRect *)frameRect
- {
- NXRect rect;
- float side;
-
- // Force the view to be a square.
- if(frameRect->size.width < frameRect->size.height)
- side = frameRect->size.width;
- else
- side = frameRect->size.height;
-
- NXSetRect(&rect, frameRect->origin.x, frameRect->origin.y, side, side);
- self = [super setFrame:&rect];
-
- // Free the old NXImage and set up a new one.
- if(!okButtonPushed)
- {
- agarRadius = 0.90 * (bounds.size.width/2.0); // in pixels
- petriDishRadius = 0.0352778 * agarRadius; // in centimeters (using 72 dpi)
- [petriDishNXImage free];
- petriDishNXImage = [[NXImage alloc] initSize:&bounds.size];
- [petriDishNXImage lockFocus];
- drawPetriDish(bounds.size.width, bounds.size.width/2.0, agarRadius,
- petriRed, petriGreen, petriBlue);
- [petriDishNXImage unlockFocus];
-
- [gridNXImage free];
- gridNXImage = [[NXImage alloc] initSize:&bounds.size];
- [gridNXImage lockFocus];
- drawGrid(bounds.size.width, bounds.size.width/2.0, agarRadius, gridDelta);
- [gridNXImage unlockFocus];
-
- [spotsNXImage free];
- spotsNXImage = [[NXImage alloc] initSize:&bounds.size];
- if(numSpots)
- [self drawSpotsInNXImage:numSpots];
- [self display];
- }
-
- if(inspector != nil)
- [inspector perform:@selector(revert:) with:self];
- okButtonPushed = NO;
- return self;
- }
-
- - initFrame:(NXRect *)frameRect
- {
- NXSize cursorSize = {16.0, 16.0};
-
- self = [super initFrame:frameRect];
-
- // Initialize the instance variables.
- gridState = NO;
- gridSpacing = 1.0; // centimeters
- agarRadius = 0.90 * (bounds.size.width/2.0); // in pixels
- petriDishRadius = 0.0352778 * agarRadius; // in centimeters (using 72 dpi)
- petriRed = 1.0;
- petriGreen = 1.0;
- petriBlue = 0.4902;
- agarColor = NXConvertRGBAToColor(petriRed, petriGreen, petriBlue, 1.0);
- spotRed = 0.0;
- spotGreen = 0.0;
- spotBlue = 0.0;
- spotColor = NXConvertRGBAToColor(spotRed, spotGreen, spotBlue, 1.0);
- numSpots = 0;
-
- petriDishNXImage = [[NXImage alloc] initSize:&bounds.size];
- [petriDishNXImage lockFocus];
- drawPetriDish(bounds.size.width, bounds.size.width/2.0, agarRadius,
- petriRed, petriGreen, petriBlue);
- [petriDishNXImage unlockFocus];
-
- spotRadius = 5; // In millimeters.
- dotRadius = spotRadius * ONEMILLIMETER; // in pixels
- gridDelta = ONECENTIMETER; // in pixels
-
- gridNXImage = [[NXImage alloc] initSize:&bounds.size];
- [gridNXImage lockFocus];
- drawGrid(bounds.size.width, bounds.size.width/2.0, agarRadius, gridDelta);
- [gridNXImage unlockFocus];
-
- spotsNXImage = [[NXImage alloc] initSize:&bounds.size];
-
- spotNXImageSize.width = 2 * dotRadius + 2.0;
- spotNXImageSize.height = 2 * dotRadius + 2.0;
- spotNXImage = [[NXImage alloc] initSize:&spotNXImageSize];
- [spotNXImage lockFocus];
- drawSpot(spotNXImageSize.width, spotNXImageSize.width/2.0, dotRadius,
- spotRed, spotGreen, spotBlue);
- [spotNXImage unlockFocus];
-
- okButtonPushed = NO;
-
- // Set up the cursor.
- clickCursorNXImage = [[NXImage alloc] initSize:&cursorSize];
- [clickCursorNXImage lockFocus];
- drawCursor();
- [clickCursorNXImage unlockFocus];
-
- clickCursor = [[NXCursor allocFromZone:[self zone]]
- initFromImage:clickCursorNXImage];
- return self;
- }
-
- // Turn grid on or off. If it is on, draw it with the specified spacing. Composites the grid
- // onto the petri dish.
- - turnGridOn:(BOOL)flag withSpacing:(float)spacing
- {
- gridState = flag;
- if(gridState)
- {
- gridSpacing = spacing; // in centimeters
- gridDelta = spacing * ONECENTIMETER; // in pixels
- [gridNXImage lockFocus];
- drawGrid(bounds.size.width, bounds.size.width/2.0, agarRadius, gridDelta);
- [gridNXImage unlockFocus];
- }
- [self display];
- return self;
- }
-
- // Set the radius of the agar. Draws the petriDishNXImage. Does not redraw the petri dish.
- - setAgarRadius:(float)radius
- {
- petriDishRadius = radius; // in centimeters
- agarRadius = radius * ONECENTIMETER; // in pixels
- if(agarRadius >bounds.size.width / 2.0)
- {
- agarRadius = bounds.size.width / 2.0;
- petriDishRadius = agarRadius / ONECENTIMETER;
- }
-
- [petriDishNXImage lockFocus];
- drawPetriDish(bounds.size.width, bounds.size.width/2.0, agarRadius,
- petriRed, petriGreen, petriBlue);
- [petriDishNXImage unlockFocus];
-
- // Draw the spots NXImage.
- if(numSpots)
- [self drawSpotsInNXImage:numSpots];
-
- // Draw the grid NXImage.
- if(gridState)
- {
- [gridNXImage lockFocus];
- drawGrid(bounds.size.width, bounds.size.width/2.0, agarRadius, gridDelta);
- [gridNXImage unlockFocus];
- }
- return self;
- }
-
- // Set the color of the agar. Draws the petriDishNXImage. Does not redraw the petri dish.
- - setAgarColor:(NXColor)color
- {
- float alpha = 1.0;
-
- agarColor = color;
- NXConvertColorToRGBA(agarColor, &petriRed, &petriGreen, &petriBlue, &alpha);
-
- [petriDishNXImage lockFocus];
- drawPetriDish(bounds.size.width, bounds.size.width/2.0, agarRadius,
- petriRed, petriGreen, petriBlue);
- [petriDishNXImage unlockFocus];
- return self;
- }
-
- // Set the color of the spots. Redraws the spotNXImage and spotsNXImage.
- // Does not redraw the petri dish.
- - setSpotColor:(NXColor)color
- {
- float alpha = 1.0;
-
- spotColor = color;
- NXConvertColorToRGBA(spotColor, &spotRed, &spotGreen, &spotBlue, &alpha);
-
- // Draw the spot NXImage.
- [spotNXImage lockFocus];
- drawSpot(spotNXImageSize.width, spotNXImageSize.width/2.0, dotRadius,
- spotRed, spotGreen, spotBlue);
- [spotNXImage unlockFocus];
-
- // Draw the spots NXImage.
- if(numSpots)
- [self drawSpotsInNXImage:numSpots];
- return self;
- }
-
- // Set the radius of the spots. Redraws the spotNXImage and spotsNXImage.
- // Does not redraw the petri dish.
- - setSpotRadius:(float)radius
- {
- spotRadius = radius; // In millimeters.
- dotRadius = spotRadius * ONEMILLIMETER; // In pixels.
-
- if(dotRadius > 0.5 * agarRadius)
- {
- dotRadius = 0.5 * agarRadius;
- spotRadius = dotRadius / ONEMILLIMETER;
- }
-
- spotNXImageSize.width = 2 * dotRadius + 2.0;
- spotNXImageSize.height = 2 * dotRadius + 2.0;
- [spotNXImage free];
- spotNXImage = [[NXImage alloc] initSize:&spotNXImageSize];
-
- // Draw the spot NXImage.
- [spotNXImage lockFocus];
- drawSpot(spotNXImageSize.width, spotNXImageSize.width/2.0, dotRadius,
- spotRed, spotGreen, spotBlue);
- [spotNXImage unlockFocus];
-
- // Draw the spots NXImage.
- if(numSpots)
- [self drawSpotsInNXImage:numSpots];
- return self;
- }
-
- // Draws the spotNXImage and the spots spotsNXImage. Does not redraw the petri dish.
- - setNumSpots:(int)spots
- {
- numSpots = spots;
-
- // Draw the spots NXImage.
- [self drawSpotsInNXImage:numSpots];
- return self;
- }
-
- // Draws the petri dish and the spots and grid if necessary.
- - drawSelf:(NXRect *)rects :(int)count
- {
- NXPoint origin = {0.0, 0.0};
-
- [petriDishNXImage composite:NX_COPY toPoint:&origin];
-
- if(numSpots)
- [spotsNXImage composite:NX_SOVER toPoint:&origin];
-
- if(gridState)
- [gridNXImage composite:NX_SOVER toPoint:&origin];
- return self;
- }
-
- - drawPetriDishWithSpots:(int)spots
- {
- [self setNumSpots:spots];
- [self display];
- return self;
- }
-
- // Draws the spots in an NXImage for the petri dish. Does not redraw the petri dish.
- - drawSpotsInNXImage:(int)spots;
- {
- float maxRadius, halfWidth, randomRadius, randomAngle, spotHalfWidth ;
- NXPoint origin;
- int spot;
-
- // Composite spots into spotsNXImage.
- [spotsNXImage lockFocus];
- PSsetalpha(0.0);
- NXRectFill(&bounds);
- PSsetalpha(1.0);
-
- maxRadius = agarRadius - dotRadius;
- halfWidth = bounds.size.width / 2.0;
- spotHalfWidth = spotNXImageSize.width/2.0;
-
- numSpots = spots;
- for (spot = 0; spot < numSpots; spot++)
- {
- randomRadius = maxRadius * random() / 2147483647.0;
- randomAngle = 6.28319 * random() / 2147483647.0;
- origin.x = randomRadius * cos(randomAngle) + halfWidth - spotHalfWidth;
- origin.y = randomRadius * sin(randomAngle) + halfWidth - spotHalfWidth;
- [spotNXImage composite:NX_SOVER toPoint:&origin];
- }
- [spotsNXImage unlockFocus];
- return self;
- }
-
- - (float)gridSpacing
- {
- return gridSpacing; // In centimeters
- }
-
- - (BOOL)gridState
- {
- return gridState;
- }
-
- - (float)petriDishRadius
- {
- return petriDishRadius; // In centimeters
- }
-
- - (int)numSpots
- {
- return numSpots;
- }
-
- - (float)spotRadius
- {
- return spotRadius; // In millimeters.
- }
-
- - okPushed:(BOOL)flag
- {
- okButtonPushed = flag;
- return self;
- }
-
- - setInspector:anObject
- {
- inspector = anObject;
- return self;
- }
-
- - (NXColor) agarColor
- {
- return agarColor;
- }
-
- - (NXColor) spotColor
- {
- return spotColor;
- }
-
- // Increment the count each time we click in the petri dish.
- - mouseDown:(NXEvent *)theEvent
- {
- clicks++;
- if(clickCountTextField)
- [clickCountTextField setIntValue:clicks];
- return self;
- }
-
- // Set the count back to zero.
- - resetClickCount:sender
- {
- clicks = 0;
- if(clickCountTextField)
- [clickCountTextField setIntValue:clicks];
- return self;
- }
-
- - (int)clickCount
- {
- return clicks;
- }
-
- - resetCursorRects
- {
- [self addCursorRect:&bounds cursor:clickCursor];
- return self;
- }
-
- - write:(NXTypedStream *)typedStream
- {
- [super write:typedStream];
- NXWriteObject(typedStream, petriDishNXImage);
- NXWriteObject(typedStream, gridNXImage);
- NXWriteObject(typedStream, spotsNXImage);
- NXWriteObject(typedStream, spotNXImage);
- NXWriteObject(typedStream, clickCountTextField);
- NXWriteObject(typedStream, clickCursor);
- NXWriteSize(typedStream, &spotNXImageSize);
- NXWriteTypes(typedStream, "{if}", &gridState, &gridSpacing);
- NXWriteTypes(typedStream, "{ff}", &agarRadius, &petriDishRadius);
- NXWriteTypes(typedStream, "{fff}", &petriRed, &petriGreen, &petriBlue);
- NXWriteTypes(typedStream, "{fff}", &spotRed, &spotGreen, &spotBlue);
- NXWriteTypes(typedStream, "{ii}", &numSpots, &okButtonPushed);
- NXWriteTypes(typedStream, "{ff}", &spotRadius, &dotRadius);
- return self;
- }
-
- - read:(NXTypedStream *)typedStream
- {
- [super read:typedStream];
- petriDishNXImage = NXReadObject(typedStream);
- gridNXImage = NXReadObject(typedStream);
- spotsNXImage = NXReadObject(typedStream);
- spotNXImage = NXReadObject(typedStream);
- clickCountTextField = NXReadObject(typedStream);
- clickCursor = NXReadObject(typedStream);
- NXReadSize(typedStream, &spotNXImageSize);
- NXReadTypes(typedStream, "{if}", &gridState, &gridSpacing);
- NXReadTypes(typedStream, "{ff}", &agarRadius, &petriDishRadius);
- NXReadTypes(typedStream, "{fff}", &petriRed, &petriGreen, &petriBlue);
- NXReadTypes(typedStream, "{fff}", &spotRed, &spotGreen, &spotBlue);
- NXReadTypes(typedStream, "{ii}", &numSpots, &okButtonPushed);
- NXReadTypes(typedStream, "{ff}", &spotRadius, &dotRadius);
- return self;
- }
-
- - awake
- {
- agarColor = NXConvertRGBAToColor(petriRed, petriGreen, petriBlue, 1.0);
- spotColor = NXConvertRGBAToColor(spotRed, spotGreen, spotBlue, 1.0);
- clicks = 0;
- return self;
- }
-
- @end